package cn.com.anypay.manager.controller.notify;

import cn.com.anypay.manager.common.utils.AnyJsonUtils;
import cn.com.anypay.manager.dto.config.payment.AlipayAppConfig;
import cn.com.anypay.manager.dto.config.payment.WxAppConfig;
import cn.com.anypay.manager.dto.config.payment.WxpayMerchantConfig;
import cn.com.anypay.manager.dto.config.payment.WxpayServiceProviderConfig;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.Base64;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/pay/notify")
public class PayNotifyController {
    private static final Logger log = LoggerFactory.getLogger(PayNotifyController.class);

    @Autowired(required = false)
    @Qualifier("alipayAppConfig")
    private AlipayAppConfig alipayAppConfig;

    @Autowired(required = false)
    @Qualifier("alipayIsvAppConfig")
    private AlipayAppConfig alipayIsvAppConfig;

    @Autowired(required = false)
    @Qualifier("wxPayMpConfig")
    private WxAppConfig wxPayMpConfig;

    @Autowired(required = false)
    @Qualifier("wxPayServiceProviderConfig")
    private WxpayServiceProviderConfig wxPayServiceProviderConfig;

    @Autowired(required = false)
    @Qualifier("wxPayMerchantConfig")
    private WxpayMerchantConfig wxPayMerchantConfig;

    // 支付宝普通商户通知
    @PostMapping("/alipay")
    public String handleAlipayNotify(@RequestParam Map<String, String> params) {
        try {
            log.info("=== 收到支付宝普通商户支付通知 ===");
            return handleAlipayPaymentNotify(params, alipayAppConfig);
        } catch (Exception e) {
            log.error("处理支付宝普通商户通知异常: {}", e.getMessage(), e);
            return "fail";
        }
    }

    // 支付宝服务商通知
    @PostMapping("/alipay-isv")
    public String handleAlipayIsvNotify(@RequestParam Map<String, String> params) {
        try {
            log.info("=== 收到支付宝服务商支付通知 ===");
            return handleAlipayPaymentNotify(params, alipayIsvAppConfig);
        } catch (Exception e) {
            log.error("处理支付宝服务商通知异常: {}", e.getMessage(), e);
            return "fail";
        }
    }

    // 微信支付普通商户通知
    @PostMapping("/wechat")
    public String handleWechatNotify(@RequestBody String notifyData,
            @RequestHeader("Wechatpay-Signature") String signature,
            @RequestHeader("Wechatpay-Timestamp") String timestamp,
            @RequestHeader("Wechatpay-Nonce") String nonce,
            @RequestHeader("Wechatpay-Serial") String serial) {
        try {
            log.info("=== 收到微信支付普通商户通知 ===");
            return handleWechatPaymentNotify(notifyData, signature, timestamp, nonce, serial, false);
        } catch (Exception e) {
            log.error("处理微信支付普通商户通知异常: {}", e.getMessage(), e);
            return "fail";
        }
    }

    // 微信支付服务商通知
    @PostMapping("/wechat-isv")
    public String handleWechatIsvNotify(@RequestBody String notifyData,
            @RequestHeader("Wechatpay-Signature") String signature,
            @RequestHeader("Wechatpay-Timestamp") String timestamp,
            @RequestHeader("Wechatpay-Nonce") String nonce,
            @RequestHeader("Wechatpay-Serial") String serial) {
        try {
            log.info("=== 收到微信支付服务商通知 ===");
            return handleWechatPaymentNotify(notifyData, signature, timestamp, nonce, serial, true);
        } catch (Exception e) {
            log.error("处理微信支付服务商通知异常: {}", e.getMessage(), e);
            return "fail";
        }
    }

    // 处理支付宝支付通知
    private String handleAlipayPaymentNotify(Map<String, String> params, AlipayAppConfig config) throws Exception {
        log.info("通知参数: {}", params);

        // 1. 验证签名
        String sign = params.remove("sign");
        String signType = params.remove("sign_type");
        boolean verifyResult = verifyAlipayCallback(params, sign, signType, config);
        if (!verifyResult) {
            log.warn("签名验证失败");
            return "fail";
        }

        // 2. 记录通知数据
        String tradeStatus = params.get("trade_status");
        String orderNo = params.get("out_trade_no");
        String tradeNo = params.get("trade_no");
        String totalAmount = params.get("total_amount");
        String buyerId = params.get("buyer_id");
        String buyerLogonId = params.get("buyer_logon_id");
        String subMerchantId = params.get("sub_merchant_id");

        log.info("=== 支付通知详情 ===");
        log.info("订单号: {}", orderNo);
        log.info("交易号: {}", tradeNo);
        log.info("支付金额: {}", totalAmount);
        log.info("交易状态: {}", tradeStatus);
        log.info("买家ID: {}", buyerId);
        log.info("买家账号: {}", buyerLogonId);
        log.info("商户ID: {}", subMerchantId);

        // 3. 返回处理结果
        if ("TRADE_SUCCESS".equals(tradeStatus)) {
            log.info("支付成功: orderNo={}, tradeNo={}", orderNo, tradeNo);
            return "success";
        } else if ("WAIT_BUYER_PAY".equals(tradeStatus)) {
            log.info("等待买家付款: orderNo={}", orderNo);
            return "success";
        } else if ("TRADE_CLOSED".equals(tradeStatus)) {
            log.info("交易已关闭: orderNo={}", orderNo);
            return "success";
        } else {
            log.warn("未知交易状态: status={}, orderNo={}", tradeStatus, orderNo);
            return "fail";
        }
    }

    // 处理微信支付通知
    private String handleWechatPaymentNotify(String notifyData, String signature, String timestamp,
            String nonce, String serial, boolean isIsv) throws Exception {
        log.info("通知数据: {}", notifyData);

        // 1. 验证签名
        String message = timestamp + "\n" + nonce + "\n" + notifyData + "\n";
        boolean verifyResult = verifyWechatPayCallbackSignature(message, signature, serial, isIsv);
        if (!verifyResult) {
            log.warn("签名验证失败");
            return "fail";
        }

        // 2. 解密回调数据
        String decryptedData = decryptWechatData(notifyData, isIsv);

        // 3. 解析回调数据
        Map<String, Object> notifyMap = AnyJsonUtils.toMap(decryptedData);

        // 4. 处理支付结果
        String orderNo = (String) notifyMap.get("out_trade_no");
        String transactionId = (String) notifyMap.get("transaction_id");
        String tradeState = (String) notifyMap.get("trade_state");
        String subMchId = (String) notifyMap.get("sub_mchid");

        log.info("=== 支付通知详情 ===");
        log.info("订单号: {}", orderNo);
        log.info("交易号: {}", transactionId);
        log.info("交易状态: {}", tradeState);
        log.info("商户号: {}", subMchId);

        if ("SUCCESS".equals(tradeState)) {
            log.info("支付成功: orderNo={}, tradeNo={}", orderNo, transactionId);
            return "success";
        } else {
            log.warn("支付未成功: status={}, orderNo={}", tradeState, orderNo);
            return "fail";
        }
    }

    // 验证支付宝回调签名
    private boolean verifyAlipayCallback(Map<String, String> params, String sign, String signType, AlipayAppConfig config) throws Exception {
        // 1. 参数排序
        Map<String, String> sortedParams = new TreeMap<>(params);

        // 2. 拼接参数
        String signStr = sortedParams.entrySet().stream()
            .map(entry -> entry.getKey() + "=" + entry.getValue())
            .collect(Collectors.joining("&"));

        // 3. 读取支付宝公钥
        String alipayPublicKey = config.getAlipayPublicKey();
        alipayPublicKey = alipayPublicKey.replace("-----BEGIN PUBLIC KEY-----", "")
                                       .replace("-----END PUBLIC KEY-----", "")
                                       .replaceAll("\\s+", "");

        // 4. 验证签名
        java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("RSA");
        java.security.spec.X509EncodedKeySpec keySpec = new java.security.spec.X509EncodedKeySpec(
            Base64.getDecoder().decode(alipayPublicKey)
        );
        java.security.PublicKey rsaPublicKey = keyFactory.generatePublic(keySpec);

        java.security.Signature signature = java.security.Signature.getInstance("SHA256withRSA");
        signature.initVerify(rsaPublicKey);
        signature.update(signStr.getBytes(StandardCharsets.UTF_8));

        return signature.verify(Base64.getDecoder().decode(sign));
    }

    // 验证微信支付回调签名
    private boolean verifyWechatPayCallbackSignature(String message, String signature, String serial, boolean isIsv) throws Exception {
        // 1. 获取平台证书
        String platformCertPath = isIsv ?
            wxPayServiceProviderConfig.getPlatformCertPath() :
            wxPayMerchantConfig.getPlatformCertPath();

        String platformCert = new String(java.nio.file.Files.readAllBytes(java.nio.file.Paths.get(platformCertPath)));

        // 2. 移除证书头尾和换行符
        platformCert = platformCert.replace("-----BEGIN CERTIFICATE-----", "")
                                 .replace("-----END CERTIFICATE-----", "")
                                 .replaceAll("\\s+", "");

        // 3. Base64解码证书
        byte[] certBytes = Base64.getDecoder().decode(platformCert);

        // 4. 创建X509Certificate
        java.security.cert.CertificateFactory cf = java.security.cert.CertificateFactory.getInstance("X.509");
        java.security.cert.X509Certificate cert = (java.security.cert.X509Certificate) cf.generateCertificate(
            new java.io.ByteArrayInputStream(certBytes)
        );

        // 5. 获取公钥
        java.security.PublicKey publicKey = cert.getPublicKey();

        // 6. 创建签名实例
        java.security.Signature sig = java.security.Signature.getInstance("SHA256withRSA");
        sig.initVerify(publicKey);

        // 7. 更新签名数据
        sig.update(message.getBytes(StandardCharsets.UTF_8));

        // 8. 验证签名
        byte[] signatureBytes = Base64.getDecoder().decode(signature);
        return sig.verify(signatureBytes);
    }

    // 解密微信支付数据
    private String decryptWechatData(String encryptedData, boolean isIsv) throws Exception {
        // 1. 解析加密数据
        Map<String, Object> rawDataMap = AnyJsonUtils.toMap(encryptedData);
        Map<String, String> dataMap = new HashMap<>();
        if (rawDataMap != null) {
            rawDataMap.forEach((key, value) -> dataMap.put(key, String.valueOf(value)));
        }
        String ciphertext = dataMap.get("ciphertext");
        String nonce = dataMap.get("nonce");
        String associatedData = dataMap.get("associated_data");

        // 2. 获取商户API密钥
        String apiKey = isIsv ?
            wxPayServiceProviderConfig.getMchApiKeyV2() :
            wxPayMerchantConfig.getMchApiKeyV2();

        // 3. 解密数据
        byte[] keyBytes = apiKey.getBytes(StandardCharsets.UTF_8);
        byte[] nonceBytes = nonce.getBytes(StandardCharsets.UTF_8);
        byte[] associatedDataBytes = associatedData != null ? associatedData.getBytes(StandardCharsets.UTF_8) : new byte[0];
        byte[] ciphertextBytes = Base64.getDecoder().decode(ciphertext);

        // 4. 使用AES-GCM解密
        javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("AES/GCM/NoPadding");
        javax.crypto.SecretKey key = new javax.crypto.spec.SecretKeySpec(keyBytes, "AES");
        javax.crypto.spec.GCMParameterSpec gcmSpec = new javax.crypto.spec.GCMParameterSpec(128, nonceBytes);
        cipher.init(javax.crypto.Cipher.DECRYPT_MODE, key, gcmSpec);
        cipher.updateAAD(associatedDataBytes);

        byte[] decryptedBytes = cipher.doFinal(ciphertextBytes);
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }

    // 测试日志接口
    @GetMapping("/test")
    public String testLog() {
        log.info("=== 测试日志输出 ===");
        log.debug("这是一条DEBUG日志");
        log.info("这是一条INFO日志");
        log.warn("这是一条WARN日志");
        log.error("这是一条ERROR日志");
        return "success";
    }
}